home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / msysjour / vol05 / 02 / clipbrd / bitmap2.c < prev    next >
Text File  |  1990-03-01  |  18KB  |  607 lines

  1. /*
  2.  * WINDOWS CLIPBOARD VIEWER - BITMAP FORMAT SOURCE CODE
  3.  *
  4.  * LANGUAGE      : Microsoft C5.1
  5.  * MODEL         : small
  6.  * ENVIRONMENT   : Microsoft Windows 2.1 SDK
  7.  * STATUS        : operational
  8.  *
  9.  */
  10.  
  11. #define  NOCOMM
  12.  
  13. #include <windows.h>
  14.  
  15. #define  HORZ_BORDER       2
  16. #define  VERT_BORDER       2
  17.  
  18. #define  HORZ_STEPSIZE     8
  19. #define  VERT_STEPSIZE     8
  20.  
  21. typedef struct {
  22.  HANDLE  hBmp;
  23.  HANDLE  hData;
  24.  POINT   ptOrg;
  25.  RECT    rcWnd;
  26.  RECT    rcBmp;
  27.  HDC     hScrDC;
  28.  HDC     hMemDC;
  29. } DISPINFO;
  30.  
  31. typedef DISPINFO FAR *   LPDISPINFO;
  32.  
  33. BOOL PASCAL          BitmapInit( HANDLE, WORD, WORD, LPSTR );
  34.  
  35. HANDLE FAR PASCAL    BitmapCreate( HWND, HANDLE );
  36. HANDLE FAR PASCAL    BitmapSize( HWND, HANDLE, WORD, LONG );
  37. HANDLE FAR PASCAL    BitmapHScroll( HWND, HANDLE, WORD, LONG );
  38. HANDLE FAR PASCAL    BitmapVScroll( HWND, HANDLE, WORD, LONG );
  39. HANDLE FAR PASCAL    BitmapPaint( HWND, HANDLE, WORD, LONG );
  40. HANDLE FAR PASCAL    BitmapDestroy( HWND, HANDLE );
  41.  
  42.  
  43.  
  44. /* BOOL
  45.  * BitmapInit( hInstance, wDataSegment, wHeapSize, lpszCmdLine )
  46.  *
  47.  *    hInstance      library instance handle
  48.  *    wDataSegment   library data segment
  49.  *    wHeapSize      default heap size
  50.  *    lpszCmdLine    command line arguments
  51.  *
  52.  * This function performs all the initialization necessary to use
  53.  * the bitmap viewer display dynamic library.  It is assumed that no
  54.  * local heap is used, hence no call to LocalInit.  A non-zero value
  55.  * is returned if the initialization was sucessful.
  56.  *
  57.  */
  58.  
  59. BOOL PASCAL BitmapInit(hInstance,wDataSegment,wHeapSize,lpszCmdLine)
  60.    HANDLE      hInstance;
  61.    WORD        wDataSegment;
  62.    WORD        wHeapSize;
  63.    LPSTR       lpszCmdLine;
  64. {
  65.  
  66.  /* warning level 3 compatibility */
  67.  hInstance;
  68.  wDataSegment;
  69.  wHeapSize;
  70.  lpszCmdLine;
  71.  
  72.  /* sucessful return */
  73.    return( TRUE );
  74.  
  75. }
  76.  
  77.  
  78.  
  79. /*
  80.  * BitmapCreate( hWnd, hClipData ) : HANDLE;
  81.  *
  82.  *    hWnd           handle to display window
  83.  *    hClipData      handle to current clipboard data
  84.  *
  85.  * This function performs all the initialization necessary in order
  86.  * to view a bitmap clipboard format.  A handle to a display infor-
  87.  * mation data block (the internal format of which is only known
  88.  * inside this module) which the owner is responsible for saving.
  89.  *
  90.  */
  91.  
  92. HANDLE FAR PASCAL BitmapCreate(
  93.  HWND        hWnd,
  94.  HANDLE      hClipData )
  95. {
  96.  BITMAP      Bitmap;
  97.  HANDLE      hDispInfo;
  98.  WORD        wWndWidth;
  99.  WORD        wWndHeight;
  100.  WORD        wScrollWidth;
  101.  WORD        wScrollHeight;
  102.  LPDISPINFO  lpDispInfo;
  103.  
  104.  /* reset scroll bars */
  105.  SetScrollPos( hWnd, SB_HORZ, 0, TRUE );
  106.  SetScrollPos( hWnd, SB_VERT, 0, TRUE );
  107.  
  108.  /* attempt to allocate data */
  109.  hDispInfo = GlobalAlloc( GHND, (DWORD)sizeof(DISPINFO) );
  110.  if ( hDispInfo ) {
  111.  
  112.    /* lock it down */
  113.    lpDispInfo = (LPDISPINFO)GlobalLock( hDispInfo );
  114.    if ( lpDispInfo ) {
  115.  
  116.      /* define bitmap data */
  117.      lpDispInfo->hData = hClipData;
  118.  
  119.      /* define bitmap dimensions */
  120.      GetObject( hClipData, sizeof(BITMAP), (LPSTR)&Bitmap );
  121.  
  122.      lpDispInfo->rcBmp.top = 0;
  123.      lpDispInfo->rcBmp.left = 0;
  124.      lpDispInfo->rcBmp.right  = Bitmap.bmWidth;
  125.      lpDispInfo->rcBmp.bottom = Bitmap.bmHeight;
  126.  
  127.      /* define window origin in bitmap coordinates */
  128.      lpDispInfo->ptOrg.x = -HORZ_BORDER;
  129.      lpDispInfo->ptOrg.y = -VERT_BORDER;
  130.  
  131.      /* define window dimensions */
  132.      GetClientRect( hWnd, &lpDispInfo->rcWnd );
  133.  
  134.      lpDispInfo->rcWnd.top = VERT_BORDER;
  135.      lpDispInfo->rcWnd.left = HORZ_BORDER;
  136.      lpDispInfo->rcWnd.right -= HORZ_BORDER;
  137.      lpDispInfo->rcWnd.bottom -= VERT_BORDER;
  138.  
  139.      OffsetRect( &lpDispInfo->rcWnd, -HORZ_BORDER, -VERT_BORDER );
  140.      IntersectRect( &lpDispInfo->rcWnd, &lpDispInfo->rcWnd,
  141.                     &lpDispInfo->rcBmp );
  142.      OffsetRect( &lpDispInfo->rcWnd, HORZ_BORDER, VERT_BORDER );
  143.  
  144.      wWndWidth =  lpDispInfo->rcWnd.right -  lpDispInfo->rcWnd.left;
  145.      wWndHeight = lpDispInfo->rcWnd.bottom - lpDispInfo->rcWnd.top;
  146.  
  147.      /* define scrollbar ranges */
  148.      wScrollWidth =  ( Bitmap.bmWidth  > wWndWidth ) ?
  149.                        Bitmap.bmWidth  - wWndWidth : 1;
  150.      wScrollHeight = ( Bitmap.bmHeight > wWndHeight ) ?
  151.                        Bitmap.bmHeight - wWndHeight : 1;
  152.  
  153.      SetScrollRange( hWnd, SB_HORZ, 0, wScrollWidth, FALSE );
  154.      SetScrollRange( hWnd, SB_VERT, 0, wScrollHeight, FALSE );
  155.  
  156.      /* unlock data */
  157.      GlobalUnlock( hDispInfo );
  158.  
  159.    } else {
  160.      GlobalFree( hDispInfo );
  161.      hDispInfo = NULL;
  162.    }
  163.  
  164.  }
  165.  
  166.  /* return display info handle */
  167.  return( hDispInfo );
  168.  
  169. }
  170.  
  171. /*
  172.  * BitmapSize( hWnd, hDispInfo, wParam, lParam ) : HANDLE;
  173.  *
  174.  *   hWnd        handle to display window
  175.  *   hDispInfo   handle to display information block
  176.  *   wParam      word parameter of WM_SIZE message
  177.  *   lParam      long parameter of WM_SIZE message
  178.  *
  179.  * This function resets the display information data block whenever
  180.  * the size of the display region is changed.  If successful, a
  181.  * handle to the new display information data block is returned.
  182.  * Failure to call this function whenever the size of the display
  183.  * region is changed will cause unusual display results.
  184.  *
  185.  */
  186.  
  187. HANDLE FAR PASCAL BitmapSize(
  188.  HWND      hWnd,
  189.  HANDLE    hDispInfo,
  190.  WORD      wParam,
  191.  LONG      lParam )
  192. {
  193.  WORD        wWndWidth;
  194.  WORD        wBmpWidth;
  195.  WORD        wWndHeight;
  196.  WORD        wBmpHeight;
  197.  WORD        wScrollWidth;
  198.  WORD        wScrollHeight;
  199.  LPDISPINFO  lpDispInfo;
  200.  
  201.  /* warning level 3 compatibility */
  202.  wParam;
  203.  lParam;
  204.  
  205.  /* reset scroll bars */
  206.  SetScrollPos( hWnd, SB_HORZ, 0, TRUE );
  207.  SetScrollPos( hWnd, SB_VERT, 0, TRUE );
  208.  
  209.  /* lock it down display information block */
  210.  lpDispInfo = (LPDISPINFO)GlobalLock( hDispInfo );
  211.  if ( lpDispInfo ) {
  212.  
  213.    /* define window origin in bitmap coordinates */
  214.    lpDispInfo->ptOrg.x = -HORZ_BORDER;
  215.    lpDispInfo->ptOrg.y = -VERT_BORDER;
  216.  
  217.    /* define bitmap dimensions */
  218.    wBmpWidth = lpDispInfo->rcBmp.right - lpDispInfo->rcBmp.left;
  219.    wBmpHeight = lpDispInfo->rcBmp.bottom - lpDispInfo->rcBmp.top;
  220.  
  221.    /* define window dimensions */
  222.    GetClientRect( hWnd, &lpDispInfo->rcWnd );
  223.  
  224.    lpDispInfo->rcWnd.top = VERT_BORDER;
  225.    lpDispInfo->rcWnd.left = HORZ_BORDER;
  226.    lpDispInfo->rcWnd.right -= HORZ_BORDER;
  227.    lpDispInfo->rcWnd.bottom -= VERT_BORDER;
  228.  
  229.    OffsetRect( &lpDispInfo->rcWnd, -HORZ_BORDER, -VERT_BORDER );
  230.    IntersectRect( &lpDispInfo->rcWnd, &lpDispInfo->rcWnd,
  231.                   &lpDispInfo->rcBmp );
  232.    OffsetRect( &lpDispInfo->rcWnd, HORZ_BORDER, VERT_BORDER );
  233.  
  234.    wWndWidth = lpDispInfo->rcWnd.right - lpDispInfo->rcWnd.left;
  235.    wWndHeight = lpDispInfo->rcWnd.bottom - lpDispInfo->rcWnd.top;
  236.  
  237.    /* define scrollbar ranges */
  238.    wScrollWidth=(wBmpWidth>wWndWidth) ? wBmpWidth-wWndWidth : 1;
  239.    wScrollHeight=(wBmpHeight>wWndHeight) ? wBmpHeight-wWndHeight : 1;
  240.  
  241.    SetScrollRange( hWnd, SB_HORZ, 0, wScrollWidth, FALSE );
  242.    SetScrollRange( hWnd, SB_VERT, 0, wScrollHeight, FALSE );
  243.  
  244.    /* unlock data */
  245.    GlobalUnlock( hDispInfo );
  246.  
  247.  } else
  248.    hDispInfo = NULL;
  249.  
  250.  /* return final result */
  251.  return( hDispInfo );
  252.  
  253. }
  254.  
  255. /*
  256.  * BitmapHScroll( hWnd, hDispInfo, wParam, lParam ) : HANDLE;
  257.  *
  258.  *   hWnd        handle to display window
  259.  *   hDispInfo   handle to display information block
  260.  *   wParam      current scroll code
  261.  *   lParam      current scroll parameter
  262.  *
  263.  * This function is responsible for handling all the horizontal
  264.  * scroll messages received when viewing a bitmap clipboard format.
  265.  * If necessary, changes to the display information block can be
  266.  * made.  As currently implemented, no action is taken.  The value
  267.  * returned is the handle to the updated display information block.
  268.  */
  269.  
  270. HANDLE FAR PASCAL BitmapHScroll(
  271.  HWND      hWnd,
  272.  HANDLE    hDispInfo,
  273.  WORD      wParam,
  274.  LONG      lParam )
  275. {
  276.  WORD        wWndWidth;
  277.  WORD        wBmpWidth;
  278.  WORD        wOldScrollPos;
  279.  WORD        wNewScrollPos;
  280.  WORD        wOldScrollRange;
  281.  LPDISPINFO  lpDispInfo;
  282.  
  283.  /* access display information block */
  284.  lpDispInfo = (LPDISPINFO)GlobalLock( hDispInfo );
  285.  if ( lpDispInfo ) {
  286.  
  287.    /* initialization */
  288.    wWndWidth = lpDispInfo->rcWnd.right - lpDispInfo->rcWnd.left;
  289.    wBmpWidth = lpDispInfo->rcBmp.right - lpDispInfo->rcBmp.left;
  290.  
  291.    wOldScrollPos = lpDispInfo->ptOrg.x + HORZ_BORDER;
  292.    wOldScrollRange=(wBmpWidth > wWndWidth) ? wBmpWidth-wWndWidth : 0;
  293.  
  294.    /* define display contexts (if necessary) */
  295.    if ( lpDispInfo->hScrDC == NULL ) {
  296.      lpDispInfo->hScrDC = GetDC( hWnd );
  297.      lpDispInfo->hMemDC = CreateCompatibleDC( lpDispInfo->hScrDC );
  298.      lpDispInfo->hBmp = SelectObject( lpDispInfo->hMemDC,
  299.                                       lpDispInfo->hData );
  300.    }
  301.  
  302.    /* process scroll message */
  303.    switch( wParam )
  304.      {
  305.    case SB_LINEUP : /* move left one line */
  306.      wNewScrollPos = (wOldScrollPos > HORZ_STEPSIZE) ?
  307.                       wOldScrollPos-HORZ_STEPSIZE : 0;
  308.      break;
  309.    case SB_LINEDOWN : /* move right one line */
  310.      wNewScrollPos = (wOldScrollPos+HORZ_STEPSIZE<=wOldScrollRange) ?
  311.                       wOldScrollPos+HORZ_STEPSIZE : wOldScrollRange;
  312.      break;
  313.    case SB_PAGEUP :  /* move left one page */
  314.      wNewScrollPos = (wOldScrollPos > wWndWidth) ?
  315.                       wOldScrollPos-wWndWidth : 0;
  316.      break;
  317.    case SB_PAGEDOWN : /* move right one page */
  318.      wNewScrollPos = (wOldScrollPos+wWndWidth <= wOldScrollRange) ?
  319.                       wOldScrollPos+wWndWidth : wOldScrollRange;
  320.      break;
  321.    case SB_THUMBPOSITION : /* move to an absolute position */
  322.    case SB_THUMBTRACK : /* track the current thumb position */
  323.      wNewScrollPos = (wOldScrollRange > 1) ? LOWORD(lParam) : 0;
  324.      break;
  325.    case SB_TOP : /* move to the first line */
  326.      wNewScrollPos = 0;
  327.      break;
  328.    case SB_BOTTOM : /* move to the last line */
  329.      wNewScrollPos = wOldScrollRange;
  330.      break;
  331.    case SB_ENDSCROLL : /* end scrolling */
  332.      wNewScrollPos = wOldScrollPos;
  333.      break;
  334.    }
  335.  
  336.    /* perform scroll and update (if necessary) */
  337.    if ( wNewScrollPos != wOldScrollPos ) {
  338.  
  339.      /* update window */
  340.      BitBlt(
  341.             lpDispInfo->hScrDC,
  342.             HORZ_BORDER,
  343.             VERT_BORDER,
  344.             wWndWidth,
  345.             lpDispInfo->rcWnd.bottom - lpDispInfo->rcWnd.top,
  346.             lpDispInfo->hMemDC,
  347.             wNewScrollPos,
  348.             lpDispInfo->ptOrg.y + VERT_BORDER,
  349.             SRCCOPY
  350.          );
  351.  
  352.      /* update origin & horizontal scrollbar */
  353.      lpDispInfo->ptOrg.x = wNewScrollPos - HORZ_BORDER;
  354.      SetScrollPos( hWnd, SB_HORZ, wNewScrollPos, TRUE );
  355.  
  356.    }
  357.  
  358.    /* release display context (if necessary) */
  359.    if ( (wParam == SB_ENDSCROLL)||(wParam == SB_THUMBPOSITION) ) {
  360.      SelectObject( lpDispInfo->hMemDC, lpDispInfo->hBmp );
  361.      DeleteDC( lpDispInfo->hMemDC );
  362.      ReleaseDC( hWnd, lpDispInfo->hScrDC );
  363.      lpDispInfo->hScrDC = NULL;
  364.    }
  365.  
  366.    /* unlock data */
  367.    GlobalUnlock( hDispInfo );
  368.  
  369.  } else
  370.    hDispInfo = NULL;
  371.  
  372.  /* return result */
  373.  return( hDispInfo );
  374.  
  375. }
  376.  
  377.  
  378.  
  379. /*
  380.  * BitmapVScroll( hWnd, hDispInfo, wParam, lParam ) : HANDLE;
  381.  *
  382.  *    hWnd           handle to display window
  383.  *    hDispInfo      handle to display information block
  384.  *    wParam       current scroll code
  385.  *   lParam      current scroll parameter
  386.  *
  387.  * This function is responsible for handling all the vertical scroll
  388.  * messages received when viewing a bitmap clipboard format.  If
  389.  * necessary, changes to the display information block can be made.
  390.  * As currently implemented, no action is taken.  The value returned
  391.  * is the handle to the updated display information block.
  392.  */
  393.  
  394. HANDLE FAR PASCAL BitmapVScroll(
  395.  HWND        hWnd,
  396.  HANDLE      hDispInfo,
  397.  WORD        wParam,
  398.  LONG        lParam )
  399. {
  400.  WORD        wWndHeight;
  401.  WORD        wBmpHeight;
  402.  WORD        wOldScrollPos;
  403.  WORD        wNewScrollPos;
  404.  WORD        wOldScrollRange;
  405.  LPDISPINFO  lpDispInfo;
  406.  
  407.  /* access display information block */
  408.  lpDispInfo = (LPDISPINFO)GlobalLock( hDispInfo );
  409.  if ( lpDispInfo ) {
  410.  
  411.    /* initialization */
  412.    wWndHeight = lpDispInfo->rcWnd.bottom - lpDispInfo->rcWnd.top;
  413.    wBmpHeight = lpDispInfo->rcBmp.bottom - lpDispInfo->rcBmp.top;
  414.  
  415.    wOldScrollPos = lpDispInfo->ptOrg.y + VERT_BORDER;
  416.    wOldScrollRange = (wBmpHeight > wWndHeight) ?
  417.                       wBmpHeight-wWndHeight : 0;
  418.  
  419.    /* define display contexts (if necessary) */
  420.    if ( lpDispInfo->hScrDC == NULL ) {
  421.      lpDispInfo->hScrDC = GetDC( hWnd );
  422.      lpDispInfo->hMemDC = CreateCompatibleDC( lpDispInfo->hScrDC );
  423.      lpDispInfo->hBmp = SelectObject( lpDispInfo->hMemDC,
  424.                                       lpDispInfo->hData );
  425.    }
  426.  
  427.    /* process scroll message */
  428.    switch( wParam )
  429.      {
  430.    case SB_LINEUP : /* move up one line */
  431.      wNewScrollPos = (wOldScrollPos > VERT_STEPSIZE) ?
  432.                       wOldScrollPos-VERT_STEPSIZE : 0;
  433.      break;
  434.    case SB_LINEDOWN : /* move down one line */
  435.      wNewScrollPos=(wOldScrollPos+VERT_STEPSIZE<=wOldScrollRange) ?
  436.                     wOldScrollPos+VERT_STEPSIZE : wOldScrollRange;
  437.      break;
  438.    case SB_PAGEUP :  /* move up one page */
  439.      wNewScrollPos=(wOldScrollPos > wWndHeight) ?
  440.                     wOldScrollPos-wWndHeight : 0;
  441.      break;
  442.    case SB_PAGEDOWN : /* move down one page */
  443.      wNewScrollPos=(wOldScrollPos+wWndHeight<=wOldScrollRange) ?
  444.                     wOldScrollPos+wWndHeight : wOldScrollRange;
  445.      break;
  446.    case SB_THUMBPOSITION : /* move to an absolute position */
  447.    case SB_THUMBTRACK : /* track the current thumb position */
  448.      wNewScrollPos = (wOldScrollRange > 1) ? LOWORD(lParam) : 0;
  449.      break;
  450.    case SB_TOP : /* move to the first line */
  451.      wNewScrollPos = 0;
  452.      break;
  453.    case SB_BOTTOM : /* move to the last line */
  454.      wNewScrollPos = wOldScrollRange;
  455.      break;
  456.    case SB_ENDSCROLL : /* end scrolling */
  457.      wNewScrollPos = wOldScrollPos;
  458.      break;
  459.    }
  460.  
  461.    /* perform scroll and update (if necessary) */
  462.    if ( wNewScrollPos != wOldScrollPos ) {
  463.  
  464.      /* update window */
  465.      BitBlt(
  466.             lpDispInfo->hScrDC,
  467.             HORZ_BORDER,
  468.             VERT_BORDER,
  469.             lpDispInfo->rcWnd.right - lpDispInfo->rcWnd.left,
  470.             wWndHeight,
  471.             lpDispInfo->hMemDC,
  472.             lpDispInfo->ptOrg.x + HORZ_BORDER,
  473.             wNewScrollPos,
  474.             SRCCOPY
  475.          );
  476.  
  477.      /* update origin & horizontal scrollbar */
  478.      lpDispInfo->ptOrg.y = wNewScrollPos - VERT_BORDER;
  479.      SetScrollPos( hWnd, SB_VERT, wNewScrollPos, TRUE );
  480.  
  481.    }
  482.  
  483.    /* release display context (if necessary) */
  484.    if ( (wParam == SB_ENDSCROLL)||(wParam == SB_THUMBPOSITION) ) {
  485.      SelectObject( lpDispInfo->hMemDC, lpDispInfo->hBmp );
  486.      DeleteDC( lpDispInfo->hMemDC );
  487.      ReleaseDC( hWnd, lpDispInfo->hScrDC );
  488.      lpDispInfo->hScrDC = NULL;
  489.    }
  490.  
  491.    /* unlock data */
  492.    GlobalUnlock( hDispInfo );
  493.  
  494.  } else
  495.    hDispInfo = NULL;
  496.  
  497.  /* return result */
  498.  return( hDispInfo );
  499.  
  500. }
  501.  
  502.  
  503.  
  504. /*
  505.  * BitmapPaint( hWnd, hDispInfo, wParam, lParam ) : HANDLE;
  506.  *
  507.  *   hWnd        handle to display window
  508.  *   hDispInfo   handle to display information block
  509.  *   wParam      WM_PAINT word parameter
  510.  *   lParam      WM_PAINT long parameter
  511.  *
  512.  * This function is responsible for handling all the paint related
  513.  * aspects for the bitmap clipboard format.  This function calculates
  514.  * the required update portion of the window and BitBlts the bitmap
  515.  * into the region.  The handle returned by this function is to the
  516.  * update display information block.
  517.  *
  518.  */
  519.  
  520. HANDLE FAR PASCAL BitmapPaint(
  521.  HWND        hWnd,
  522.  HANDLE      hDispInfo,
  523.  WORD        wParam,
  524.  LONG        lParam )
  525. {
  526.  PAINTSTRUCT Ps;
  527.  HDC         hMemDC;
  528.  HANDLE      hOldData;
  529.  LPDISPINFO  lpDispInfo;
  530.  
  531.  /* warning level 3 compatibility */
  532.  wParam;
  533.  lParam;
  534.  
  535.  /* access display information block */
  536.  lpDispInfo = (LPDISPINFO)GlobalLock( hDispInfo );
  537.  if ( lpDispInfo ) {
  538.  
  539.    /* start paint operation */
  540.    BeginPaint( hWnd, &Ps );
  541.  
  542.    /* define update region */
  543. IntersectRect(&Ps.rcPaint,&Ps.rcPaint,&lpDispInfo->rcWnd );
  544.    OffsetRect(&Ps.rcPaint,lpDispInfo->ptOrg.x,lpDispInfo->ptOrg.y );
  545. IntersectRect(&Ps.rcPaint,&Ps.rcPaint,&lpDispInfo->rcBmp );
  546.    OffsetRect(&Ps.rcPaint,-lpDispInfo->ptOrg.x,-lpDispInfo->ptOrg.y);
  547.  
  548.    /* perform BitBlt operation */
  549.    hMemDC = CreateCompatibleDC( Ps.hdc );
  550.    if ( hMemDC ) {
  551.      hOldData = SelectObject( hMemDC, lpDispInfo->hData );
  552.      BitBlt(
  553.             Ps.hdc,
  554.             Ps.rcPaint.left,
  555.             Ps.rcPaint.top,
  556.             Ps.rcPaint.right - Ps.rcPaint.left,
  557.             Ps.rcPaint.bottom - Ps.rcPaint.top,
  558.             hMemDC,
  559.             Ps.rcPaint.left + lpDispInfo->ptOrg.x,
  560.             Ps.rcPaint.top + lpDispInfo->ptOrg.y,
  561.             SRCCOPY
  562.            );
  563.      SelectObject( hMemDC, hOldData );
  564.      DeleteDC( hMemDC );
  565.    }
  566.  
  567.    /* unlock data & end paint operation */
  568.    GlobalUnlock( hDispInfo );
  569.    EndPaint( hWnd, &Ps );
  570.  
  571.  } else
  572.    hDispInfo = NULL;
  573.  
  574.  /* return final result */
  575.  return( hDispInfo );
  576.  
  577. }
  578.  
  579. /*
  580.  * BitmapDestroy( hWnd, hDispInfo ) : HANDLE;
  581.  *
  582.  *   hWnd        handle to display window
  583.  *   hDispInfo   handle to display information block
  584.  *
  585.  * This function is to be called whenever the display region is being
  586.  * destroyed.  It is responsible for restoring the system to it's
  587.  * original state and for releasing any memory or resources defined.
  588.  * The value returned is the handle to the OLD display information
  589.  * block.  This handle should NEVER be used after this function is
  590.  * called.  If an error occurs a value of NULL is returned.
  591.  *
  592.  */
  593.  
  594. HANDLE FAR PASCAL BitmapDestroy(
  595.  HWND      hWnd,
  596.  HANDLE    hDispInfo )
  597. {
  598.  
  599.  /* warning level 3 compatibility */
  600.  hWnd;
  601.  
  602.  /* free allocated memory block & return old handle */
  603.  GlobalFree( hDispInfo );
  604.  return( hDispInfo );
  605.  
  606. }
  607.